# -*- coding: utf-8 -*-

#   Copyright (C) 2011  P.L. Lucas, P.L. del Castillo
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.

import pygtk
pygtk.require('2.0')
import gtk
import cairo
import os
import math
from config import *
from fxdialog import *
from image_ops import *

#Listado de efectos. En cada subclase de FX hay que indicar correctamente el self.class_base en __init__
def fx_list():
	list={
			'None': FX,
			'Fade In': FXFadeIn,
			'Fade Out': FXFadeOut,
			'Rotate 90 left': FXRotate90Left,
			'Rotate 90 right': FXRotate90Right,
			'Zoom and move': FXZoomAndMove,
			'Circle Open': FXCircleOpen,
			'Circle Close': FXCircleClose
		}
	return list

#Lista de clases de efectos.

#FX: Esta es la clase de la que derivan todos los efectos
class FX:
	def __init__(self, videoProperties, duration):
		self.videoProperties=videoProperties
		self.pixbuf=None
		self.duration=duration
		self.class_base=FX
		self.icon_path=None
		self.xml_tag_name='effect'
	
	def get_name(self):
		return self.class_name()
	
	def class_name(self):
		for k,v in fx_list().iteritems():
			if self.class_base==v:
				return k 
		return None
	
	def init_from_data(self, attrs):
		#attrs es un diccionario con las propiedades
		for k,v in attrs.iteritems():
			if v[0].isdigit() or v[0]=='-':
				i='self.'+k+'='+str(v)
			else:
				i='self.'+k+'="'+str(v)+'"'
			x=compile(i, '<string>', 'exec')
			eval(x)
	
	def xml(self):
		return self.xml_generate([])
	
	def xml_generate(self, variables):
		x=  '\t<'+self.xml_tag_name+'>\n'
		x=x+'\t\t<name>'+self.get_name()+'</name>\n'
		for k in variables:
			x+='\t\t<'+k+'>'+str(eval('self.'+k))+'</'+k+'>\n'
		x=x+'\t</'+self.xml_tag_name+'>\n'
		return x
	
	def show_menu(self, parent):
		pass

	def set_duration(self, duration):
		self.duration=duration
	
	def icon_resize(self, pixbuf):
		return image_adjust_pixbuf_to_size( pixbuf, 64*self.videoProperties.width/self.videoProperties.height, 64)
		#return pixbuf.scale_simple(64*pixbuf.get_width()/pixbuf.get_height(),64,gtk.gdk.INTERP_BILINEAR)
	
	def icon_add_icon(self, pixbuf, icon_path,x, y):
		pix=self.icon_resize(pixbuf)
		pixmap=gtk.gdk.Pixmap(None, pix.get_width(), pix.get_height(), 24)
		ct=pixmap.cairo_create()
		ct.set_source_pixbuf(pix,0,0)
		ct.paint()
		pix1=gtk.gdk.pixbuf_new_from_file(icon_path)
		pix1=pix1.scale_simple(pix.get_height()/4, pix.get_height()/4,gtk.gdk.INTERP_BILINEAR)
		ct.set_source_pixbuf(pix1,x,y)
		ct.paint_with_alpha(0.8)
		pix=gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8,  pix.get_width(), pix.get_height())
		pix=pix.get_from_drawable(pixmap, pixmap.get_colormap(), 0,0,0,0,  pix.get_width(), pix.get_height())
		return pix
	
	def icon(self, pixbuf, i=0):
		if self.icon_path!=None:
			return self.icon_add_icon(pixbuf, self.icon_path,64/4*i, 0)
		return self.icon_resize(pixbuf)
		
	def adjust_pixbuf_to_video_screen(self, pixbuf):
		return image_adjust_pixbuf_to_size(pixbuf, self.videoProperties.width, self.videoProperties.height)
	
	def render_start(self):
		self.FX_render_start()
	def render(self, pixbuf, t):
		if self.pixbuf==pixbuf:
			return self.frame
		else:
			self.pixbuf=pixbuf
		if pixbuf.get_width()==self.videoProperties.width and pixbuf.get_height()==self.videoProperties.height:
			self.frame=pixbuf
			return pixbuf
		else:
			self.frame=imageSurface_adjust_pixbuf_to_size( pixbuf, self.videoProperties.width, self.videoProperties.height)
			return self.frame
	def render_end(self):
		self.FX_render_end()
	
	def FX_render_end(self):
		self.pixbuf=None
		self.frame=None
	def FX_render_start(self):
		self.pixbuf=None
		self.frame=None

class FXFadeIn(FX):
	def __init__(self, videoProperties, duration):
		FX.__init__(self, videoProperties, duration)
		self.class_base=FXFadeIn
		self.icon_path=install_path+'/icons/fadein.svg'
	def render(self, pixbuf, t):
		im, ct=imageSurface_new(self.videoProperties.width, self.videoProperties.height)
		ct.set_source_pixbuf(imageSurface_adjust_pixbuf_to_size( pixbuf, self.videoProperties.width, self.videoProperties.height),0,0)
		alpha=float(t)/float(self.duration)
		if alpha>1.0:
			alpha=1.0
		ct.paint_with_alpha(alpha)
		return imageSurface_get_pixbuf(im)

class FXFadeOut(FX):
	def __init__(self, videoProperties, duration):
		FX.__init__(self, videoProperties, duration)
		self.class_base=FXFadeOut
		self.icon_path=install_path+'/icons/fadeout.svg'
	def render(self, pixbuf, t):
		im, ct=imageSurface_new(self.videoProperties.width, self.videoProperties.height)
		ct.set_source_pixbuf(imageSurface_adjust_pixbuf_to_size( pixbuf, self.videoProperties.width, self.videoProperties.height),0,0)
		alpha=float(self.duration-t)/float(self.duration)
		if alpha<0.0:
			alpha=0.0
		ct.paint_with_alpha(alpha)
		return imageSurface_get_pixbuf(im)

class FXRotate90Left(FX):
	def __init__(self, videoProperties, duration):
		FX.__init__(self, videoProperties, duration)
		self.class_base=FXRotate90Left
		self.icon_path=install_path+'/icons/rotate90left.svg'
	def render(self, pixbuf, t):
		if self.pixbuf==pixbuf:
			return self.frame
		else:
			self.pixbuf=pixbuf
		im, ct=imageSurface_new(self.videoProperties.width, self.videoProperties.height)
		ct.translate(0, self.videoProperties.height)
		ct.rotate(-3.14159/2.0)
		ct.set_source_pixbuf(imageSurface_adjust_pixbuf_to_size( pixbuf, self.videoProperties.height, self.videoProperties.width),0,0)
		ct.paint()
		self.frame=imageSurface_get_pixbuf(im)
		return self.frame

class FXRotate90Right(FX):
	def __init__(self, videoProperties, duration):
		FX.__init__(self, videoProperties, duration)
		self.class_base=FXRotate90Right
		self.icon_path=install_path+'/icons/rotate90right.svg'

	def render(self, pixbuf, t):
		if self.pixbuf==pixbuf:
			return self.frame
		else:
			self.pixbuf=pixbuf
		im, ct=imageSurface_new(self.videoProperties.width, self.videoProperties.height)
		ct.translate(self.videoProperties.width, 0)
		ct.rotate(3.14159/2.0)
		ct.set_source_pixbuf(imageSurface_adjust_pixbuf_to_size( pixbuf, self.videoProperties.height, self.videoProperties.width),0,0)
		ct.paint()
		self.frame=imageSurface_get_pixbuf(im)
		return self.frame




class FXZoomAndMove(FX):
	def __init__(self, videoProperties, duration):
		FX.__init__(self, videoProperties, duration)
		self.class_base=FXZoomAndMove
		self.icon_path=install_path+'/icons/zoomout.svg'
		#Properties of widget
		self.angle_start=0.0
		self.angle_end=0.0
		self.zoom_start=1
		self.zoom_end=1
		self.x_start=0.4
		self.x_end=0.6
		self.y_start=0.5
		self.y_end=0.5
		self.n_claves=1
		self.i=0
	
	def xml(self):
		return self.xml_generate(['duration', 'angle_start', 'angle_end', 'zoom_start', 'zoom_end', 'x_start', 'x_end', 'y_start', 'y_end', 'n_claves'])
	
	def show_menu(self, parent):
		dialog=FXDialog(parent)
		dialog.text_entry('Angle start (degrees):', 'angle_start', self.angle_start)
		dialog.text_entry('Angle end (degrees):', 'angle_end', self.angle_end)
		dialog.text_entry('Zoom start (%):', 'zoom_start', self.zoom_start*100.0)
		dialog.text_entry('Zoom end (%):', 'zoom_end', self.zoom_end*100.0)
		dialog.text_entry('x start (%):', 'x_start', self.x_start*100.0)
		dialog.text_entry('x end (%):', 'x_end', self.x_end*100.0)
		dialog.text_entry('y start (%):', 'y_start', self.y_start*100.0)
		dialog.text_entry('y end (%):', 'y_end', self.y_end*100.0)
		dialog.text_entry('Interpolate n frames (1-25):', 'n_claves', self.n_claves)
		if dialog.run():
			self.angle_start=dialog.get_text('angle_start','float')
			self.angle_end=dialog.get_text('angle_end','float')
			self.zoom_start=dialog.get_text('zoom_start','float')/100
			self.zoom_end=dialog.get_text('zoom_end','float')/100
			self.x_start=dialog.get_text('x_start','float')/100
			self.y_end=dialog.get_text('y_end','float')/100
			self.y_start=dialog.get_text('y_start','float')/100
			self.x_end=dialog.get_text('x_end','float')/100
			self.n_claves=dialog.get_text('n_claves','int')
		dialog.close()

	def render(self, pixbuf, t):
		im, ct=imageSurface_new(self.videoProperties.width, self.videoProperties.height)
		#ct.set_source_rgb(0, 0, 0)
		#ct.rectangle(0, 0, self.videoProperties.width, self.videoProperties.height)
		#ct.fill()
		#ct.paint()
		factor=float(t)/float(self.duration)
		zoom=float(self.zoom_end-self.zoom_start)*factor+float(self.zoom_start)
		angle=((self.angle_end-self.angle_start)*factor+self.angle_start)*3.14159/180.0
		width=int(float(self.videoProperties.width)*zoom+0.5)
		height=int(float(self.videoProperties.height)*zoom+0.5)
		x=(float(self.x_end-self.x_start)*float(factor)+float(self.x_start))*float(self.videoProperties.width)
		y=(float(self.y_end-self.y_start)*float(factor)+float(self.y_start))*float(self.videoProperties.height)
		ct.translate(x,y)
		ct.rotate(angle)
		#ct.scale(zoom,zoom)
		#ct.set_source_pixbuf(imageSurface_adjust_pixbuf_to_size( pixbuf, int(self.videoProperties.width*zoom), int(self.videoProperties.height*zoom)),-self.videoProperties.width*zoom/2, -self.videoProperties.height*zoom/2)
		
		w, h = pixbuf.get_width(), pixbuf.get_height()
		ct.scale(float(self.videoProperties.width*zoom)/float(w),float(self.videoProperties.width*zoom)/float(w))
		ct.set_source_pixbuf(pixbuf,-w/2, -h/2)
		
		ct.paint()
		return imageSurface_get_pixbuf(im)

class FXCircleClose(FX):
	def __init__(self, videoProperties, duration):
		FX.__init__(self, videoProperties, duration)
		self.class_base=FXCircleClose
		self.icon_path=install_path+'/icons/circleclose.svg'

	def render(self, pixbuf, t):
		im, ct=imageSurface_new(self.videoProperties.width, self.videoProperties.height)
		ct.set_source_pixbuf(imageSurface_adjust_pixbuf_to_size( pixbuf, self.videoProperties.width, self.videoProperties.height),0,0)
		radio=math.sqrt(self.videoProperties.width*self.videoProperties.width+self.videoProperties.height*self.videoProperties.height)
		alpha=radio*float(self.duration-t)/float(self.duration)
		if alpha>=radio:
			alpha=0.99*radio
		radial = cairo.RadialGradient(self.videoProperties.width*0.5, self.videoProperties.height*0.5, alpha, self.videoProperties.width*0.5, self.videoProperties.height*0.5, radio)
		radial.add_color_stop_rgba(0, 0, 0, 0, 1)
		radial.add_color_stop_rgba(0.05, 0, 0, 0, 0)
		ct.mask(radial)
		return imageSurface_get_pixbuf(im)


class FXCircleOpen(FX):
	def __init__(self, videoProperties, duration):
		FX.__init__(self, videoProperties, duration)
		self.class_base=FXCircleOpen
		self.icon_path=install_path+'/icons/circleopen.svg'

	def render(self, pixbuf, t):
		im, ct=imageSurface_new(self.videoProperties.width, self.videoProperties.height)
		ct.set_source_pixbuf(imageSurface_adjust_pixbuf_to_size( pixbuf, self.videoProperties.width, self.videoProperties.height),0,0)
		radio=math.sqrt(self.videoProperties.width*self.videoProperties.width+self.videoProperties.height*self.videoProperties.height)
		if t<self.duration:
			alpha=radio*float(t)/float(self.duration)
		else:
			ct.paint()
			alpha=radio
		radial = cairo.RadialGradient(self.videoProperties.width*0.5, self.videoProperties.height*0.5, alpha, self.videoProperties.width*0.5, self.videoProperties.height*0.5, radio)
		radial.add_color_stop_rgba(0, 0, 0, 0, 1)
		radial.add_color_stop_rgba(0.05, 0, 0, 0, 0)
		ct.mask(radial)
		return imageSurface_get_pixbuf(im)


